package com.xmhmyh.generalframework.project.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.xmhmyh.generalframework.common.BaseServiceImpl;
import com.xmhmyh.generalframework.common.enums.ResponseCode;
import com.xmhmyh.generalframework.common.utils.MyBeanUtils;
import com.xmhmyh.generalframework.common.utils.MyListUtils;
import com.xmhmyh.generalframework.framework.exceptions.ManageExceptions;
import com.xmhmyh.generalframework.project.sys.dto.RoleDTO;
import com.xmhmyh.generalframework.project.sys.entity.*;
import com.xmhmyh.generalframework.project.sys.enums.RoleStatus;
import com.xmhmyh.generalframework.project.sys.mapper.MenuMapper;
import com.xmhmyh.generalframework.project.sys.mapper.RoleMapper;
import com.xmhmyh.generalframework.project.sys.mapper.RoleMenuMapper;
import com.xmhmyh.generalframework.project.sys.mapper.UserRoleMapper;
import com.xmhmyh.generalframework.project.sys.service.IMenuService;
import com.xmhmyh.generalframework.project.sys.service.IRoleMenuService;
import com.xmhmyh.generalframework.project.sys.service.IRoleService;
import com.xmhmyh.generalframework.project.sys.vo.MenuVO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.yaml.snakeyaml.events.Event;

import javax.annotation.Resource;
import java.awt.dnd.DropTargetListener;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: 于丁
 * @DateTime: 2020/7/24 9:09 上午
 */
@Service
public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, Role> implements IRoleService {
    @Resource
    private UserRoleMapper userRoleMapper;
    @Autowired
    private IRoleMenuService roleMenuService;
    @Autowired
    private IMenuService menuService;


    @Override
    public List<UserRole> getUserRolesByUserId(Long userId) {
        LambdaQueryWrapper<UserRole> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserRole::getUserId, userId);
        return userRoleMapper.selectList(queryWrapper);
    }


    @Override
    public List<RoleMenu> getRoleMenusByRoleIds(List<Long> roleIds) {
        QueryWrapper<RoleMenu> queryWrapper = new QueryWrapper<>();
        // 加 distinct 是为了去重
        queryWrapper.select("distinct role_id,menu_id");
        queryWrapper.in("role_id", roleIds);
        List<RoleMenu> roleMenuList = roleMenuService.list(queryWrapper);
        return roleMenuList;
    }

    @Override
    public Role findByRoleCode(String roleCode) {
        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Role::getCode, roleCode);
        List<Role> roleList = list(queryWrapper);
        return roleList.size() == 1 ? roleList.get(0) : null;
    }

    @Override
    public List<Long> loadByRoleIdHandler(Long roleId) {
        // 获取角色的所有权限
        List<Menu> menuList = menuService.getMenuByRoleIds(MyListUtils.genList(roleId));

        // 获取所有菜单的父ID
        List<Long> superIds = menuList.stream().map(menu -> {
            return menu.getParentId();
        }).collect(Collectors.toList());
        // 判断所有菜单中没有子组件的则为末端组件
        // 判断组件的ID是否在整个劣币啊种是否有作为父ID出现，没有则为末端组件
        // 也就是判断哪个组件没有儿子就是末端组件
        List<Long> treeList = new ArrayList<>();
        for (Menu menu : menuList) {
            // 判断自己的id是不是父id
            if (!superIds.contains(menu.getId())) {
                treeList.add(menu.getId());
            }
        }
        return treeList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveHandler(User user, RoleDTO roleDTO) {
        Role role = null;
        Boolean add = false;
        if (roleDTO.getId() == null) {
            add = true;
            role = new Role();
            MyBeanUtils.setSysInfo(role, user.getId(), user.getAccountId());
            role.setId(uidGenerator.getUID());
            role.setStatus(RoleStatus.NORMAL.getValue());
        } else {
            role = getById(roleDTO.getId());
            if (role == null) {
                throw new ManageExceptions(ResponseCode.ROLE_NO_FOUND);
            }
        }
        role.setName(roleDTO.getName());
        role.setCode(roleDTO.getCode());
        role.setRemark(roleDTO.getRemark());
        if (add) {
            save(role);
        } else {
            updateById(role);
        }
        // 更新角色的权限
        updateRoleMenu(role.getId(), roleDTO.getCheckedMenuIds());
    }



    /**
     * @Author: 于丁
     * @Description: 更新角色菜单 1、先删除原本所有 2、添加新的
     * @DateTime: 2020/7/30 2:46 下午
     * @Params:
     * @Return
     */
    private void updateRoleMenu(Long roleId, List<Long> menuIds) {
        // 删除角色之前的菜单
        LambdaQueryWrapper<RoleMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RoleMenu::getRoleId, roleId);
        roleMenuService.remove(queryWrapper);
        // 保存新的权限
        List<RoleMenu> roleMenuList = menuIds.stream().map(menuId -> {
            return new RoleMenu(roleId, menuId);
        }).collect(Collectors.toList());
        roleMenuService.saveBatch(roleMenuList);
    }

    @Override
    public void delHandler(Long id) {
        Role role = getById(id);
        if (role == null) {
            throw new ManageExceptions(ResponseCode.ROLE_NO_FOUND);
        }
        // 删除用户角色
        LambdaQueryWrapper<UserRole> userRoleLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userRoleLambdaQueryWrapper.eq(UserRole::getRoleId, id);
        userRoleMapper.delete(userRoleLambdaQueryWrapper);
        // 删除角色菜单表
        LambdaQueryWrapper<RoleMenu> roleMenuLambdaQueryWrapper = new LambdaQueryWrapper<>();
        roleMenuLambdaQueryWrapper.eq(RoleMenu::getRoleId, id);
        roleMenuService.remove(roleMenuLambdaQueryWrapper);
        // 删除角色本身
        removeById(id);
    }

    @Override
    public List<Role> getByAccountId(Long accountId) {
        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Role::getAccountId, accountId);
        return list(queryWrapper);
    }

    @Override
    public Role getByCode(String code) {
        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Role::getCode, code);
        return getOne(queryWrapper);
    }
}
